home *** CD-ROM | disk | FTP | other *** search
-
-
- TITLE HELOWRLD
- NAME HELOWRLD
- .386
- .387
-
- ; HELOWRLD.ASM can be assembled using IBM's ALP 3.00.004 assembler,
- ; linked to make a pseudo .DLL using LINK386, and
- ; stripped to leave only the FWKTL_format program using FWKTRIM.
-
- TEXT32 SEGMENT DWORD PUBLIC 'CODE'
- ASSUME CS:FLAT, DS:FLAT
- ALIGN 4
- MAIN:
-
- ; This is a "Hello, world!" program for loading and execution in
- ; OS/2 Warp protected mode, using the FWKTL(TM) Text_program Loader,
- ; Version 1.00, to load it.
- ;
- ; (C)Copyright Frederick W. Kantor 1996. All rights reserved.
- ;
- ; programs loaded by FWKTL can modify themselves, and can modify
- ; their source (the file from which the program was loaded)
- ;
- ;
- ; To assemble in an OS/2 session using IBM's ALP 3.00.004, run
- ;
- ; MK_HWASM.CMD
- ;
- ; (enclosed in this package) and follow the instructions on the screen
- ; to make HELOWLD2.COM;
- ;
- ; the .COM extension can then be changed or removed, to help avoid
- ; error. FWKTL loads it independent of extension.
- ;
- ; if the resulting .COM program is executed directly in a DOS or OS/2
- ; environment, it returns to the command line: the first byte is RET.
- ;
- ; There are 3 examples in this "Hello, world." program. The only
- ; parameter you need to set to use them is EXAMPLE :
- ; EXAMPLE EQU 1
- ; EXAMPLE EQU 2
- ; EXAMPLE EQU 3
-
- EXAMPLE EQU 1 ; current setting
-
- ;
- ; EXAMPLE EQU 1
- ; uses PSETUP = 0 in initialization; HELOWLD2.COM is 69 bytes long;
- ; this configuration shows how to get an API's address when you
- ; already have the module handle; it gets a specific address for a
- ; single procedure, DOS32WRITE (DOSCALLS.282) (see also P_ STRUC);
- ; the handle for the DOSCALLS module is provided by FWKTL as part
- ; of the initial data.
- ;
- ; EXAMPLE EQU 2
- ; sets PSETUP = 1; HELOWRLD.COM is 41 bytes long; this uses a simple
- ; SHOW procedure in FWKTL to send an ASCIIZ string up to, but not
- ; including, its terminal 00 to 'standard output' (defaults to
- ; screen), and append a terminal carriage_return line_feed. (to save
- ; space, the exit errorlevel is not set to zero: the errorlevel
- ; returned is the low 16 bits of the DWORD for the program's entry
- ; point.)
- ;
- ; EXAMPLE EQU 3
- ; sets PSETUP = 0; HELOWLD2.COM is 142 bytes long;
- ; this illustrates how functions can be easily added; it gets
- ; addresses for a list of 25 APIs and uses two of them, one to write
- ; "Hello, world!",0d,0a to "standard output" (the screen), and the
- ; other to sound a tone. The APIs loaded in example 3 include tools
- ; for loading and freeing other dynamic link library modules,
- ; allocating and freeing memory, some semaphore procedures, etc.
-
-
- ; To run the assembled HELOWLD2.COM in an OS/2 session:
- ;
- ; Format: FWKTL HELOWLD2.COM <enter>
-
- ; Initialization:
- ;
- ; FWKTL loads a program and sets
- ;
- ; EAX = entry point for execution
- ; EBX = 0 if no free memory requested
- ; ELSE EBX DWORD aligned, after code
- ; ECX = number of DWORDs in initialization requested (see P_ STRUC)
- ; ESI points to start of initialization_data source (matching start
- ; of P_)
- ; EDI = 0 if no free memory requested
- ; ELSE EDI = EBX = start of free memory, in case you wish to put
- ; initialization data there
- ; the "direction flag" (decrement flag) is cleared (CLD)
- ;
- ; FWKTL provides initial values, and several procedures;
- ; see P_ STRUC, below, for initial values and procedure addresses.
- ; These values are easily copied, with ESI, EDI, ECX, and CLD from
- ; FWKTL. If free memory was requested (done in HELOWRLD.1), use
- ; REP MOVSD
-
- ; If no free memory was requested, save values in STACK. For saving
- ; EBX in STACK, I suggest you modify J_ STRUC and put J_EBX at the
- ; beginning, and load EDI with the effective address of the beginning
- ; of the standard FWKTL initialization values: e.g.,
- ; SUB ESP,TYPE J_
- ; MOV EBP,ESP
- ; LEA EDI,[EBP].P_LOADEDAT ; where to put initialization data
- ; REP MOVSD ; using ESI, ECX, and CLD from FWKTL
-
- ; FWKTL calls the program as a routine in Thread 1:
- ;
- ; on entry, the stack will not return an exception until 0ABAh dwords
- ; are pushed (= 02AE8h bytes = 10984 (decimal) bytes)
- ;
- ; on return to FWKTL: CS, SS, and ESP must be correct when RET
- ; is executed
- ;
- ; EAX, EBX, ECX, EDX, ESI, EDI, EBP, DS, ES, FS, GS can be changed
- ;
- ; EAX is used to return an exit errorlevel, of which the low 16 bits
- ; (AX) is returned by OS/2 Warp at the command line.
-
- ; to display exit errorlevels, you can use PROMPT=[$p $r]
-
- ;-------------------------------------------------------
-
- KEEP_EBX EQU 00 ; set to 1 to store EBX in stack, so that it can
- ; be recovered by MOV EBX,[EBP] (e.g., in case a
- ; procedure called changes it); EBP may be less
- ; likely to be changed than EBX during such calls.
- ; All calls used in these 3 examples preserve EBX,
- ; so this is not used.
- ;-------------------------------------------------------
- ; PSETUP is used to control P_ STRUC and to set
- ; bit00 in second DWORD in the program header
- ; = 0 to get the shorter initial setup data;
- ; = 1 to get the longer initial setup data which
- ; has the addresses for the SHOW and USWORDCAPS
- ; utilities
-
- IF EXAMPLE EQ 1 OR EXAMPLE EQ 3
- PSETUP EQU 0
- ELSEIF EXAMPLE EQ 2
- PSETUP EQU 1
- ENDIF
-
- ;-------------------------------------------------------
-
- ; structure for initial data:
-
- P_ STRUC ; these are provided by FWKTL for initialization,
- ; according to file header settings:
-
- P_LOADEDAT DD ? ; start of this memory block
- P_PWHENCE DD ? ; points to ASCIIZ string re where program was found
- P_PCOMTAIL DD ? ; points to ASCIIZ command tail
-
- P_GETFN DD ? ; address for indirect call to FWKTL GETFN function:
- ; Input:
- ; EAX = ProcedureOrdinal
- ; (maximum permitted OS/2 ordinal <= 65533)
- ; if EAX > 0, ESI is ignored
- ; OR
- ; EAX = 0
- ; ESI points to ASCIIZ procedure_name
- ;
- ; EDX = module handle
- ; EDI points to target DWORD to receive
- ; procedure address
- ;
- ; Output:
- ; if successful,
- ; zero_flag is set
- ; procedure address is in target DWORD
- ; EAX = 0
- ;
- ; if error
- ; zero_flag is cleared
- ; EAX contains error number:
- ; 6 ERROR_INVALID_HANDLE
- ; 123 ERROR_INVALID_NAME
- ; 65079 ERROR_ENTRY_IS_CALLGATE
- ;
- ; all other CPU registers and flags are preserved
-
- P_GETFNLIST DD ? ; address for indirect call to FWKTL GETFNLIST
- ; function, to get the addresses for a list of
- ; procedures in the same module:
- ;
- ; EBX, EDX, EBP are preserved across this function
- ;
- ; Input:
- ; EAX = 0 if list is ASCIIZ procedure_names
- ; 2 if list is WORD ordinals
- ; 4 if list is DWORD ordinals
- ; (maximum permitted OS/2 ordinal = 65533)
- ; ECX = number of items in procedure list
- ; EDX = module handle
- ; ESI points to start of list of WORDs, DWORDs,
- ; or series of ASCIIZ procedure_names
- ; EDI points to start of target DWORDs to receive
- ; the corresponding procedure addresses
- ;
- ; Output:
- ; if no error:
- ; zero_flag is set
- ; each target DWORD contains its procedure address
- ; ESI:
- ; if EAX = 0
- ; ESI points to terminal 00h of last ASCIIZ
- ; string;
- ; ELSE if EAX > 0
- ; ESI points to first byte after source;
- ; EDI points to first byte after last target DWORD
- ;
- ; if error:
- ; zero_flag is cleared
- ; EAX contains error number:
- ; 6 ERROR_INVALID_HANDLE
- ; 123 ERROR_INVALID_NAME
- ; 65079 ERROR_ENTRY_IS_CALLGATE
- ; ECX is not decremented on failed step
- ; ESI points to list item identifying the procedure
- ; for which the failure occurred
-
- P_HDOSCALLS DD ? ; handle for DOSCALLS module as loaded by FWKTL,
- ; can be used in EDX for P_GETFN or P_GETFNLIST.
-
- ;------------------------- end of setup for PSETUP EQ 0
-
- IF PSETUP EQ 1
-
- ; two additional procedures are optionally available from FWKTL:
-
- P_SHOW DD ? ; address for FWKTL SHOW function;
- ;
- ; usage:
- ;
- ; ESI points to ASCIIZ string to show on screen
- ; using 'standard error' handle=2;
- ; this procedure drops terminal 00 and adds 0D,0A;
- ; all CPU registers and flags are preserved.
-
- P_USWORDCAPS DD ? ; address for FWKTL capitalization function;
- ;
- ; usage:
- ;
- ; ESI points to contiguous string > ' ' to
- ; capitalize, US English;
- ; all CPU registers and flags are preserved.
- ;
- ; (e.g., this procedure can be used when '/' or '-'
- ; is found in command tail, for case_insensitive
- ; options when you don't capitalize whole tail)
-
- ENDIF ;------------------------- end of setup for PSETUP EQ 1
-
- IF EXAMPLE EQ 1 OR EXAMPLE EQ 3 ; these are used with an API:
-
- P_WROTE DD ? ; used with the DOS32WRITE API
-
- P_WRITE DD ? ; to hold address for OS/2 DOS32WRITE API
- ; Note: P_WRITE is also the first entry in the
- ; address targets used in EXAMPLE EQ 3:
- ; P_WROTE must not be inserted directly
- ; below P_WRITE, because it would offset
- ; the rest of the address targets in
- ; EXAMPLE EQ 3
- ENDIF
- ; other material can be inserted here:
-
- IF EXAMPLE EQ 3 ; addresses for 24 more APIs
-
- P_SCANENV DD ?
- P_SEARCHPATH DD ?
- P_SLEEP DD ?
- P_EXIT DD ?
- P_SETFILEPTR DD ?
- P_CLOSE DD ?
- P_OPEN DD ?
- P_READ DD ?
- P_BEEP DD ? ; see note on using BEEP for diagnostics, below
- P_ALLOCMEM DD ?
- P_FREEMEM DD ?
- P_CREATETHREAD DD ?
- P_GETINFOBLOCKS DD ?
- P_LOADMODULE DD ?
- P_QUERYPROCADDR DD ?
- P_FREEMODULE DD ?
- P_CREATEEVENTSEM DD ?
- P_OPENEVENTSEM DD ?
- P_CLOSEEVENTSEM DD ?
- P_RESETEVENTSEM DD ?
- P_POSTEVENTSEM DD ?
- P_WAITEVENTSEM DD ?
- P_QUERYEVENTSEM DD ?
- P_QUERYSYSINFO DD ?
-
- ENDIF ; EXAMPLE EQ 3
-
- P_ ENDS ; end of P_ STRUC
-
- ;-------------------------------------------------------
-
- ; Note: BEEP is convenient for simple diagnostics;
- ; e.g., you can insert code blocks like this to make a tone
- ; when each such place is reached, and set different values
- ; for frequency and/or duration to distinguish the beeps;
- ; registers and flags are preserved across this function:
-
-
- ; put this before the first beep call you want turned on:
- ;
- ; rundb equ 01 ; 01 to insert them (and remove initial ";"),
- ; ; 00 to exclude them
-
-
- ; if rundb ;debug
- ; pushfd ;debug
- ; pushad ;debug
- ; pushd 0100h ; duration, milliseconds ;debug
- ; pushd 0100h ; frequency, cycles per second ;debug
- ; call [ebx].p_beep ;debug
- ; add esp,08 ;debug
- ; popad ;debug
- ; popfd ;debug
- ; endif ;debug
-
- ;-------------------------------------------------------
-
- ; Here is the code header:
-
- ; the first byte of the header is a RET, in case the program has
- ; a .COM extension and someone accidentally tries to run it directly
- ; in a DOS or OS/2 session.
-
- CODESTART: ; used as a reference point
-
- RET ; 4_byte header identification string
- DB 'FWK' ;
-
- DD PSETUP ; bit00 = 0 for PSETUP=0 (see P_ STRUC)
- ; bit00 = 1 for PSETUP=1 (see P_ STRUC)
- ; bits 31...01 are reserved, and must be zero for use with
- ; FWKTL version 1.00.
-
- DD TYPE P_ ; amount of free memory requested after code;
- ; in these examples, just enough to hold a P_ STRUC;
- ; PSETUP affects the size of P_ STRUC used
- ; to hold standard FWKTL initialization data;
- ; storage of any other data there also affects the
- ; size of P_ STRUC; e.g., P_ can contain buffers.
- ; the free memory starts DWORD aligned, zeroed.
-
- ; more memory than used in P_ STRUC can be requested;
- ; note that memory requested in this way is committed
- ; when allocated.
-
- ; for efficiency and flexibility, programs which need a
- ; lot of memory can use API procedures to allocate and
- ; free memory, rather than asking for it as part of
- ; installation. EXAMPLE EQ 3 loads the addresses for
- ; calling some memory management procedures.
-
- ; Note that this kind of program can write new code into
- ; the memory and then run it, or can relocate or modify
- ; itself and continue to run.
-
-
- ; Here is where the executable code starts;
-
- JMP SHORT LL0 ; this is the execution entry point.
-
- ; at this point, the STACK from FWKTL provides working space
- ; for 0400h (1024 decimal) dwords, not counting space
- ; allowed for system use;
- ; the STACK will not return an exception until more than
- ; 0ABAh dwords are on the stack (2746 decimal)
- ; EAX = entry point for execution
- ; EBX = start of free memory, DWORD aligned, after code
- ; ECX = number of initialization DWORDs requested (P_ STRUC)
- ; ESI points to start of initialization_data source (matching
- ; start of P_)
- ; EDI=EBX to put initialization data there (using REP MOVSD)
- ; decrement flag has been cleared (CLD) (for using REP MOVSD)
-
- MSG:
- OMSG EQU $-CODESTART ; used in calculating where this message is
- DB 'Hello, world!'
-
- IF EXAMPLE EQ 2 ; the FWKTL SHOW procedure is for use with ASCIIZ strings;
- DB 00 ; terminal 00 to make ASCIIZ string (SHOW provides CRLF)
- ELSE ;
- DB 0DH,0AH ; carriage_return line_feed (for use with DOS32WRITE API)
- ENDIF ;
-
- LMSG EQU $-MSG
-
-
- IF EXAMPLE EQ 3 ; this is a flexible method, using an expandable list
- ; of procedures; in this example the procedures are
- ; identified using ordinal numbers (this is required for
- ; DOSCALLS procedures), but this method can be used with
- ; procedures identified by name, in a list of ASCIIZ
- ; procedure_names.
-
- FNLIST: ; list of procedures (DOSCALLS ordinals).
- OFNLIST EQU $-CODESTART ; offset used for finding FNLIST in memory.
-
- ; these decimal number WORDs are in the same order
- ; as their corresponding DD targets in P_ STRUC
- ; these are the procedures (APIs) included in EXAMPLE=3:
- ; decimal ordinals
-
- DW 282 ; DOS32WRITE (DOSCALLS.282)
- DW 227 ; DOS32SCANENV (DOSCALLS.227)
- DW 228 ; DOS32SEARCHPATH (DOSCALLS.228)
- DW 229 ; DOS32SLEEP (DOSCALLS.229)
- DW 234 ; DOS32EXIT (DOSCALLS.234)
- DW 256 ; DOS32SETFILEPTR (DOSCALLS.256)
- DW 257 ; DOS32CLOSE (DOSCALLS.257)
- DW 273 ; DOS32OPEN (DOSCALLS.273)
- DW 281 ; DOS32READ (DOSCALLS.281)
- DW 286 ; DOS32BEEP (DOSCALLS.286)
- DW 299 ; DOS32ALLOCMEM (DOSCALLS.299)
- DW 304 ; DOS32FREEMEM (DOSCALLS.304)
- DW 311 ; DOS32CREATETHREAD (DOSCALLS.311)
- DW 312 ; DOS32GETINFOBLOCKS (DOSCALLS.312)
- DW 318 ; DOS32LOADMODULE (DOSCALLS.318)
- DW 321 ; DOS32QUERYPROCADDR (DOSCALLS.321)
- DW 322 ; DOS32FREEMODULE (DOSCALLS.322)
- DW 324 ; DOS32CREATEEVENTSEM (DOSCALLS.324)
- DW 325 ; DOS32OPENEVENTSEM (DOSCALLS.325)
- DW 326 ; DOS32CLOSEEVENTSEM (DOSCALLS.326)
- DW 327 ; DOS32RESETEVENTSEM (DOSCALLS.327)
- DW 328 ; DOS32POSTEVENTSEM (DOSCALLS.328)
- DW 329 ; DOS32WAITEVENTSEM (DOSCALLS.329)
- DW 330 ; DOS32QUERYEVENTSEM (DOSCALLS.330)
- DW 348 ; DOS32QUERYSYSINFO (DOSCALLS.348)
-
- NFNLIST EQU ($-FNLIST)/2 ; number of items in FNLIST
- ; = list_length_in_bytes / word_length
- ENDIF ; EXAMPLE EQ 3
-
- ; Note that the APIs loaded in EXAMPLE EQ 3 include procedures for
- ; loading and freeing other modules besides DOSCALLS (which was loaded
- ; by FWKTL); the GETFN and GETFNLIST functions in FWKTL can be used
- ; with other modules than DOSCALLS, once they have been loaded and
- ; their handles made available.
-
- LL0: ; target for JMP from entry point
-
- IF KEEP_EBX ; in general use, this step is used to
- PUSH EBX ; save EBX value; but every call used in this
- ENDIF ; particular program preserves EBX, so this
- ; step is not needed.
-
- MOV EBP,ESP ; save ESP value in EBP
-
- REP MOVSD ; load EBX:P_ STRUC
- ; FWKTL preset ESI, EDI, and ECX,
- ; and did CLD
-
-
- IF EXAMPLE EQ 1 ; get specific API: DOS32WRITE (DOSCALLS.282)
-
- MOV EAX,282 ; 282 decimal ordinal
- MOV EDX,[EBX].P_HDOSCALLS ; use handle for DOSCALLS module,
- ; already loaded by FWKTL
- LEA EDI,[EBX].P_WRITE ; point EDI at DWORD for holding address
- CALL [EBX].P_GETFN ; get procedure address
-
- ENDIF
-
-
- IF EXAMPLE EQ 3 ; this is a flexible method, using an
- ; expandable list of API procedure ordinals
-
- MOV ESI,[EBX].P_LOADEDAT ; calculate position of start of FNLIST
- ADD ESI,OFNLIST ; procedure list
-
- LEA EDI,[EBX].P_WRITE ; point EDI at first location for storing
- ; procedure addresses
- MOV EAX,02 ; FNLIST list contains 2_byte ordinals
- MOV ECX,NFNLIST ; number of items in list
- MOV EDX,[EBX].P_HDOSCALLS ; use handle for DOSCALLS module,
- ; already loaded by FWKTL
- CALL [EBX].P_GETFNLIST ; get addresses for procedures in list
-
- ENDIF
-
-
- IF EXAMPLE EQ 2 ; this is a special_case, with a simple way
- ; to show a message on the screen
- ; (uses "standard error" handle=2):
-
- MOV ESI,[EBX].P_LOADEDAT ; point ESI at start of loaded program
- ADD ESI,OMSG ; add offset to point ESI at start of message
- CALL [EBX].P_SHOW ; call FWKTL SHOW function
-
- ENDIF
-
-
- IF EXAMPLE EQ 1 OR EXAMPLE EQ 3 ; this illustrates a flexible method,
- ; using the DOS32WRITE API loaded above
- ; (see HELOWRLD.LST):
-
- LEA EAX,[EBX].P_WROTE ; pDWORD for amount written
- PUSHD EAX ;
-
- PUSHD LMSG ; amount to write
-
- MOV EAX,[EBX].P_LOADEDAT ; calculate position of message text
- ADD EAX,OMSG ;
- PUSHD EAX ; push address of beginning of text
-
- PUSHD 1 ; handle = 'standard output'
-
- CALL [EBX].P_WRITE ; indirect call to DOS32WRITE to write message
- ENDIF
-
- IF EXAMPLE EQ 3
-
- ;MOV ESP,EBP ; could clear the stack first, but there's enough room
-
- IF KEEP_EBX
- MOV EBX,[EBP] ; this is a way to restore EBX
- ENDIF
-
- PUSHD 0200H ; 512 milliseconds duration (nominal)
- PUSHD 0100H ; 256 cycles per second (approx)
- CALL [EBX].P_BEEP ; indirect call to DOS32BEEP API loaded above
-
- ENDIF ; EXAMPLE EQ 3
-
- IF EXAMPLE NE 2 ; cleanup omitted in EXAMPLE EQ 2 to save space
-
- MOV ESP,EBP ; clean up STACK
- ;
- IF KEEP_EBX ;
- POP EBX ;
- ENDIF ;
-
- XOR EAX,EAX ; set exit errorlevel = 0 (low 16 bits are
- ; used in making exit errorlevel returned
- ; to command line in OS/2 Warp)
- ENDIF ; EXAMPLE NE 2
-
- RET ; return to FWKTL
-
- DB 'FWKEOF',0,1 ; EOF signature for use with FWKTRIM
-
- TEXT32 ENDS
- END MAIN
-
-
- ; FWKTL and FWKTRIM are trademarks of Frederick W. Kantor.
- ;
- ; IBM, OS/2, Warp, and IBM Assembly Language Processor (ALP) are trademarks
- ; of International Business Machines Corporation.
-